#!/usr/bin/python
# -*- coding: UTF-8 -*-

import urllib3
import base64
import uuid
import hmac
import time
import json
import hashlib
import requests
import threading
from typing import Any, Dict

urllib3.disable_warnings()


class ObjectDict(Dict[str, Any]):

    def __getattr__(self, name: str) -> Any:
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name: str, value: Any) -> None:
        self[name] = value


def synchronized(func):
    func.__lock__ = threading.Lock()

    def lock_func(*args, **kwargs):
        with func.__lock__:
            return func(*args, **kwargs)

    return lock_func


class Singleton(type):
    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        super().__init__(*args, **kwargs)

    @synchronized
    def __call__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance


class ApiHelper_Hikvision(metaclass=Singleton):
    """
    海康门禁单例模式封装，支持多线程
    """

    def __init__(self, appKey, appSecret, hostname):
        self.appKey = appKey
        self.appSecret = appSecret
        self.hostname = hostname
        self.base_url = f'https://{self.hostname}'

    def sign(self, key, value):
        temp = hmac.new(key.encode(), value.encode(), digestmod=hashlib.sha256)
        return base64.b64encode(temp.digest()).decode()

    def headers(self, api_get_address_url):
        x_ca_nonce = str(uuid.uuid4())
        x_ca_timestamp = str(int(round(time.time()) * 1000))
        sign_str = "POST\n*/*\napplication/json" + "\nx-ca-key:" + self.appKey + "\nx-ca-nonce:" + \
                   x_ca_nonce + "\nx-ca-timestamp:" + x_ca_timestamp + "\n" + \
                   api_get_address_url
        signature = self.sign(self.appSecret, sign_str)
        headers = {
            "Accept": "*/*",
            "Content-Type": "application/json",
            "x-ca-key": self.appKey,  # appKey，即 AK
            "x-ca-signature-headers": "x-ca-key,x-ca-nonce,x-ca-timestamp",
            "x-ca-signature": signature,  # 需要计算得到的签名，此处通过后台得到
            "x-ca-timestamp": x_ca_timestamp,  # 时间戳
            "x-ca-nonce": x_ca_nonce  # UUID，结合时间戳防重复
        }
        return headers

    def check_result(self, response):
        if response.status_code == 200:
            params = ObjectDict(**(response.json()))
            if params['code'] != "0":
                raise ValueError("数据获取失败")
            return params
        raise ValueError("接口请求失败")

    def GetAcsDeviceList(self, body):
        """
        查询门禁设备列表v2
        body:
        {
            "pageNo": 1,
            "pageSize": 1000
        }
        """
        api_get_address_url = '/artemis/api/resource/v2/acsDevice/search'
        url = self.base_url + api_get_address_url
        results = requests.post(url, data=json.dumps(body),
                                headers=self.headers(api_get_address_url), verify=False)
        return self.check_result(results)

    def GetOnlineAcsDevice(self, body):
        """
        获取门禁设备在线状态
        body:
        {
            "regionId": "root000000",
            "ip": "10.33.43.135",
            "indexCodes": [
                "f98y8c28y85y7y213c082yu95yu"
            ],
            "status": "1",
            "pageNo": 1,
            "pageSize": 20,
            "includeSubNode": "1"
        }
        """
        api_get_address_url = '/artemis/api/nms/v1/online/acs_device/get'
        url = self.base_url + api_get_address_url
        results = requests.post(url, data=json.dumps(body),
                                headers=self.headers(api_get_address_url), verify=False)
        return self.check_result(results)

    def GetDoorStates(self, body):
        """
        查询门禁点状态
        body:
        {"doorIndexCodes": [indexCode]}
        """
        api_get_address_url = '/artemis/api/acs/v1/door/states'
        url = self.base_url + api_get_address_url
        results = requests.post(url, data=json.dumps(body),
                                headers=self.headers(api_get_address_url), verify=False)
        return self.check_result(results)

    def GetDoorEvents(self, body):
        """查询门禁点事件v2
        body:
        {
            "pageNo": i, "pageSize": 1000,
            "doorIndexCodes": [devSn],
            "startTime": startTime, "endTime": endTime
        }
        """
        api_get_address_url = '/artemis/api/acs/v2/door/events'
        url = self.base_url + api_get_address_url
        results = requests.post(url, data=json.dumps(body),
                                headers=self.headers(api_get_address_url), verify=False)
        return self.check_result(results)


if __name__ == '__main__':
    # 示例如下

    appKey = '29300945'
    appSecret = 'Rd4TC97gCqMm94JVkxMi'
    hostname = '172.16.112.2'
    api_get_address_url = "/artemis/api/resource/v1/cameras"
    config = {
        "appKey": appKey,
        "appSecret": appSecret,
        "hostname": hostname
    }
    ApiHelper_Hikvision = ApiHelper_Hikvision(**config)
    body = {
        "pageNo": 1,
        "pageSize": 100,
    }
    url = ApiHelper_Hikvision.base_url + api_get_address_url
    results = requests.post(url, data=json.dumps(body),
                            headers=ApiHelper_Hikvision.headers(api_get_address_url), verify=False)
    print(ApiHelper_Hikvision.check_result(results))
